/**
 * Copyright 2011 Andreas Kaubisch
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/
package de.easymessage.internal;

import java.util.ArrayList;
import java.util.List;

import de.easymessage.Channel;
import de.easymessage.ChannelListener;
import de.easymessage.ChannelMessage;
import de.easymessage.ChannelPublisher;
import de.easymessage.ChannelPublisherFactory;
import de.easymessage.ExternalPublisher;
import de.easymessage.MessageService;

public class DefaultMessageService implements MessageService, ExternalPublisher {

	List<Channel<?>> channelList;
	private ChannelPublisher<?> publisher;
	private ChannelPublisherFactory factory;
	
	public DefaultMessageService() {
		this(new DefaultChannelPublisherFactory());
	}
	
	public DefaultMessageService(ChannelPublisher<?> publisher) {
		channelList = new ArrayList<Channel<?>>();
		this.publisher = publisher;
	}
	
	public DefaultMessageService(ChannelPublisherFactory factory) {
		channelList = new ArrayList<Channel<?>>();
		this.factory = factory;
	}
	
	
	@SuppressWarnings("unchecked")
	@Override
	public void publish(String channelName, ChannelMessage<?> message) {
		Channel<?> channel = getChannel(channelName);
		
		if(channel != null && message != null && isPublisherAvailable()) {
			ChannelPublisher<?> publisher = getPublisher(channel);
			publisher.publish((ChannelMessage)message);
		}
	}

	private boolean isPublisherAvailable() {
		return factory != null || publisher != null;
	}
	
	private ChannelPublisher<?> getPublisher(Channel<?> channel) {
		ChannelPublisher<?> publisher = null; 
		if(factory != null)  
			publisher = factory.createPublisher(channel);
		else if(this.publisher != null)
			publisher = this.publisher;
		return publisher;
	}

	@Override
	public void subscribe(String channelName, ChannelListener<?> listener) {
		if(listener == null)
			throw new IllegalArgumentException("listener must be an instance");
		
		Channel channel = createChannelIfNecessary(channelName);
		if(!channel.contains(listener)) {
			channel.addListener(listener);
		}
	}

	@Override
	public void unsubscribe(ChannelListener<?> listener) {
		if(listener == null)
			throw new IllegalArgumentException("listener must be an instance");

		for(Channel channel : channelList) {
			if(channel.contains(listener)) {
				channel.removeListener(listener);
			}
		}
	}

	private synchronized Channel createChannelIfNecessary(String channelName) {
		Channel requestedChannel = getChannel(channelName);
		
		//create new Channel if it doesnt exists
		if(requestedChannel == null) {
			requestedChannel = new Channel(channelName);
			channelList.add(requestedChannel);
		}
		
		return requestedChannel;
	}

	private Channel getChannel(String channelName) {
		if(channelName == null || "".equals(channelName))
			throw new IllegalArgumentException("name of channel required");

		Channel requestedChannel = null;
		
		for(Channel channel : channelList) {
			if(channelName.equalsIgnoreCase(channel.getName())) {
				requestedChannel = channel;
			}
		}
		
		return requestedChannel;
	}

	@Override
	public void setChannelPublisherFactory(ChannelPublisherFactory factory) {
		this.factory = factory;
	}

	@Override
	public ChannelPublisherFactory getChannelPublisherFactory() {
		return factory;
	}
}
